use super::{
    err, err_value, json, ok, throw_err, Base, CSend, Client, Collect, ECode, KeyNode, Lock, MapSv,
    Resp, SvCache, VBase, VMap, Value,
};
use std::collections::HashMap;

pub struct Station;

impl Base for Station {}

impl Station {
    pub async fn do_cmd(
        &self,
        para: &Value,
        cmd: &str,
        client: &Client,
        cache: SvCache,
        lock: Lock,
        tx: CSend,
    ) -> Resp {
        let data = para.ckobj()?;
        let line = data.ck_str("line")?;

        let collect = Collect::new(client, cache, line);

        match cmd {
            "addpsn" => {
                let sub = self.sub_type(data);
                let sn = data.ck_str("k")?;
                let val = data.ck_array("v")?;
                let k_sn = collect.key_sub_sn("station", &sub, sn)?;

                let _ = lock.lock().await;

                let mut put = Vec::new();
                collect.merge_mass_vec(&k_sn, val, &mut put)?;

                collect.commit_que(Some(&put), None, &tx).await?;

                ok!()
            }
            "rmpsn" => {
                let sub = self.sub_type(data);
                let sn = data.ck_str("k")?;
                let item = data.ck_str("sn")?;
                let k_sn = collect.key_sub_sn("station", &sub, sn)?;

                let _ = lock.lock().await;

                let mut put = Vec::new();
                let mut del = Vec::new();

                collect.del_mass_item(&k_sn, item, &mut put, &mut del);
                collect.commit_que(Some(&put), Some(&del), &tx).await?;

                ok!()
            }
            "getpsn" => {
                let sn = data.ck_str("k")?;

                let mut ret = HashMap::new();

                if let Ok(body) = collect.item_sub_sn("station", "psn", sn).await {
                    ret.insert("psn", body);
                }

                if let Ok(body) = collect.item_sub_sn("station", "rework", sn).await {
                    ret.insert("rework", body);
                }

                if ret.is_empty() {
                    throw_err!(ECode::EmptyData, "no data");
                }

                ok!(ret)
            }
            "adduser" | "rmuser" | "getuser" => {
                collect.do_sub_cmd("station", cmd, para, "user", lock).await
            }
            "addequip" | "rmequip" | "getequip" => {
                collect
                    .do_sub_cmd("station", cmd, para, "equip", lock)
                    .await
            }
            _ => {
                let count = data
                    .k_bool("count")
                    .map(|_| vec!["user".to_string(), "equip".to_string()]);

                collect.do_cmd("station", cmd, para, lock, count).await
            }
        }
    }

    fn sub_type(&self, data: &MapSv) -> String {
        let rework = match data.k_bool("rework") {
            Some(v) => v,
            None => false,
        };

        let ret = if rework { "rework" } else { "psn" };

        ret.to_string()
    }
}
